/* [file: WDI/Source/Processor/scanner.l] */
/*
 * WDI: Web Development Interface
 *
 * Copyright (c) 2009 - 2010, ODIS, Rizo Isrofov <irm@odisproject.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *   * Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *   * Neither the name of the ODIS nor the names of its contributors may be
 *     used to endorse or promote products derived from this software without
 *     specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY ODIS ''AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL ODIS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

%{

	#include <stdio.h>
	#include <string.h>
	#include <type.h>
	#include <adt.h>
	#include "parser.h"

	#define MAX_STR_SIZE 100

	extern unsigned int line_cnt;
	extern char *progname;

	/**
	 * \brief	Checks if the given id is a wdi-type.
	 * \param	id Identifier to be tested.
	 * \return	True if the `id` is a type and false otherwise
	 */
	bool is_type(const char *id);
	extern char *type[];

	void echo();
	void warning(const char* msg);

	/* String helpers */
	char string_buffer[MAX_STR_SIZE];
	char *string_buffer_ptr;
	void save_string();
	void set_string_value();
%}

identifier      [a-zA-Z_][A-Za-z0-9_]*
integer         [-+]?[0-9]+
whitespace      [ \t]+
EOL             \n

%option nounput noinput noyywrap
%x STRING_LITERAL STRING_BLOCK

%%

	/* Statement tokens. */
for     { return(FOR); }
include { return(INCLUDE); }
in      { return(IN); }

	/* General tokens */
{identifier} {
	yylval.string = strdup(yytext);
	if (is_type(yytext)) {
		echo(yylval.string, "TYPE");
		return TYPE;
	} else {
		echo(yylval.string, "IDENTIFIER");
		return IDENTIFIER;
	}
}

{integer} {
	yylval.integer = atoi(yytext);
	echo(yytext, "INTEGER");
	return INTEGER;
}

	/* String tokens */
\" {
	string_buffer_ptr = string_buffer;
	BEGIN STRING_LITERAL;
}

<STRING_LITERAL>
{
	\" {
		BEGIN(0);
		set_string_value();
		echo(yylval.string, "STRING");
		return STRING_LITERAL;
	}

	[^"\n]+ {
		save_string();
	}
}

\"{3} {
	string_buffer_ptr = string_buffer;
	BEGIN STRING_BLOCK;
}

<STRING_BLOCK>
{
	\"{3} {
		BEGIN(0);
		set_string_value();
		echo(yylval.string, "STRING");
		return STRING_BLOCK;
	}

	.|\n { /* BUG(?): Set the negation of triple quote. */
		save_string();
	}
}

{whitespace} { /* Ignore whitespace. */ }

{EOL} { line_cnt++; }

[{}()=;,] { /* TODO: Add all single-character symbols. */
	return *yytext;
}

. { warning("Unknown character"); }

%%

bool is_type(const char* id)
{
	char** tag_ptr = type;

	/*
	 * TODO[6]: Use a faster searching method
	 *          (exempli gratia: hash table).
	 */
	while(*tag_ptr != NULL)
		if (strcmp(*tag_ptr, id) == 0)
			return true;
		else
			tag_ptr++;

	return false;
}

void echo(char *str, char *toktype)
{
	printf(">> %c[1;34m token[%s]:%c[0m %s\n", 27, toktype, 27, str);
}

void warning(const char* msg)
{
	fprintf(stderr, "[Line %d] %s: %s\n", line_cnt, msg, yytext);
}

inline void save_string()
{
	char *y_ptr = yytext;
	while(*y_ptr)
		*string_buffer_ptr++ = *y_ptr++;
}

inline void set_string_value()
{
	*string_buffer_ptr = '\0';
	yylval.string = strdup(string_buffer);
}
